﻿using DotNetExtensions.AspNet.SQLites.Attributes;
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Text;

namespace DotNetExtensions.AspNet.SQLites
{
    public class SQLiteBuilder : Singleton<SQLiteBuilder>
    {
        public List<TableInfo> Tables { get; private set; }
        private SQLiteBuilder()
        {
            // take all tables
            Tables = new List<TableInfo>();
            var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();

            var clazz = assemblies.SelectMany(a => a.GetExportedTypes()).Where(c => c.IsClass).Distinct().ToList();

            foreach (var item in clazz)
            {
                var attrs = item.GetCustomAttributes(typeof(SQLiteTableAttribute), false);

                if (attrs.Any()) Tables.Add(TableInfoFactory.Default.Get(item));
            }
        }


        public bool Exists(string connectionString, out string filename)
        {
            filename = string.Empty;
            if (connectionString.IndexOf(';') > 0)
            {
                // Data Source=xxx.db;xxxx
                string[] splits = connectionString.Split(';');
                foreach (var item in splits)
                {
                    if (item.Replace(" ", "").ToLower().Contains("datasource="))
                    {
                        filename = item.Substring(item.IndexOf('=') + 1);
                        break;
                    }
                }
            }
            else if (connectionString.Replace(" ", "").ToLower().Contains("datasource="))
            {
                filename = connectionString.Substring(connectionString.IndexOf('=') + 1);
            }

            if (string.IsNullOrEmpty(filename)) throw new Exception("sqlite db connecting string invalid");

            return File.Exists(filename);
        }

        public void Initialize(SQLiteConnectionInfo connectionInfo, bool force = false)
        {
            if (!Exists(connectionInfo.ConnectionString, out string filename))
            {
                connectionInfo.FileName = filename;
                using (File.Create(filename)) { };
            }
            else if (force)
            {
                Flush(connectionInfo);
                connectionInfo = SQLiteConnectionFactory.Default.Create(connectionInfo.ConnectionString);
            }

            using (var connection = connectionInfo.Connection)
            {
                foreach (var item in Tables)
                {
                    var createCommandText = item.CreateCommandText;

                    using (var command = connection.CreateCommand())
                    {
                        command.CommandText = createCommandText;
                        command.ExecuteNonQuery();
                    }
                }
            }
        }

        public void Flush(SQLiteConnectionInfo connectionInfo)
        {
            if (!Exists(connectionInfo.ConnectionString, out string filename))
            {
                connectionInfo.FileName = filename; return;
            }

            using (var connection = connectionInfo.Connection)
            {
                foreach (var item in Tables)
                {
                    var dropCommandText = item.DropCommandText;

                    using (var command = connection.CreateCommand())
                    {
                        command.CommandText = dropCommandText;
                        command.ExecuteNonQuery();
                    }
                }
            }
        }
    }
}
